package com.tjd.uploaddemo.controller;

import com.tjd.uploaddemo.utils.Dto;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @Auther: 田金东
 * @Date: 12/11/0011
 **/
@RestController
public class TestController {

    private final static String EXCEL_2003_L = ".xls";    //2003- 版本的excel
    private final static String EXCEL_2007_U = ".xlsx";   //2007+ 版本的excel

    /**
     * 缓存处理线程
     */
    private final static Map<String, DealThread> threadMap = new HashMap<>();

    /**
     * 文件上传接口（处理文件）
     * @param file
     * @return
     * @throws Exception
     */
    @PostMapping("/uploadFile")
    public Dto<Object> uploadExcel(MultipartFile file) throws Exception {
        Dto<Object> dto = new Dto<>();
        //生成WorkBook
        Workbook workbook = getWorkbook(file.getInputStream(), file.getOriginalFilename());
        //处理Excel文件
        String dealId = dealExcel(workbook);
        //将处理线程的ID返回给前端
        dto.setData(dealId);
        return dto;
    }

    /**
     * 实时返回处理进度的接口
     * @param dealId
     * @return
     */
    @GetMapping("/getDealPercent")
    public Dto<Object> getDealPercent(String dealId) {
        Dto<Object> dto = new Dto<>();
        //根据前端传来的Id获取处理线程
        DealThread dealThread = threadMap.get(dealId);
        if (dealThread == null) {
            dto.errorMsg("处理已结束");
            return dto;
        }
        //获取处理进度
        double dealPercent = dealThread.getDealPercent();
        dto.setData(dealPercent);
        return dto;
    }

    /**
     * 创建一个线程处理对应的工作簿
     * @param workbook
     * @return 处理线程的ID
     */
    public String dealExcel(Workbook workbook) {
        //处理线程的ID
        String id = UUID.randomUUID().toString();
        DealThread dealThread = new DealThread(id, workbook);
        Thread thread = new Thread(dealThread);
        threadMap.put(id, dealThread);
        thread.start();
        return id;
    }

    /**
     * 描述：根据文件后缀，自适应上传文件的版本
     *
     * @param inStr,fileName
     * @return
     * @throws Exception
     */
    public Workbook getWorkbook(InputStream inStr, String fileName) throws Exception {
        Workbook wb = null;
        String fileType = fileName.substring(fileName.lastIndexOf("."));
        if (EXCEL_2003_L.equals(fileType)) {
            wb = new HSSFWorkbook(inStr);  //2003-
        } else if (EXCEL_2007_U.equals(fileType)) {
            wb = new XSSFWorkbook(inStr);  //2007+
        } else {
            throw new Exception("解析的文件格式有误！");
        }
        return wb;
    }

    /**
     * 文件的处理线程
     */
    private class DealThread implements Runnable {

        private String dealId;
        private Workbook workbook;
        private final int MAX_ROW_NUM;
        private int currentRowNum = 0;

        /**
         * 获取处理进度
         *
         * @return
         */
        public double getDealPercent() {
            return currentRowNum * 1.0 / MAX_ROW_NUM;
        }

        public DealThread(String dealId, Workbook workbook) {
            this.dealId = dealId;
            this.workbook = workbook;
            Sheet sheetAt = workbook.getSheetAt(0);
            MAX_ROW_NUM = sheetAt.getLastRowNum() + 1;
        }

        public boolean isFinished() {
            return MAX_ROW_NUM <= currentRowNum;
        }

        @Override
        public void run() {
            Sheet sheet = workbook.getSheetAt(0);
            for (Row row : sheet) {
                try {
                    //休眠30毫秒，模拟复杂的处理过程
                    Thread.sleep(30);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                currentRowNum++;
            }
        }
    }
}
